import os

from .adpu import *
from smartcard.CardConnection import CardConnection
from smartcard.System import readers
from smartcard.reader import Reader
import logging
import tomlkit

logger = logging.getLogger(__name__)
logger.propagate = False
formatter = logging.Formatter('%(asctime)s %(message)s')
file_handler = logging.FileHandler('card-ops.log', encoding='utf-8')
file_handler.setFormatter(formatter)
file_handler.setLevel(logging.DEBUG)
logger.addHandler(file_handler)
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)

config_file = os.path.join(
    os.path.dirname(os.path.abspath(__file__)), 'readers.toml')


def get_reader() -> Reader:
    """根据readers.json中的读卡器名称，查询可用的读卡器"""
    available_readers = {r.name:r for r in readers()}
    with open(config_file, 'r') as f:
        reader_config = tomlkit.load(f)

    for tbl_name, tbl_item in reader_config.items():
        if tbl_name.startswith('reader_'):
            reader_name = tbl_item['name']
            if reader_name in available_readers:
                return available_readers[reader_name]
    return None


def transmit(card: CardConnection, cadpu: CAdpu) -> RAdpu:
    """封装的CardConnection的transmit方法

    将格式封装为输入CAdpu，输出RAdpu。
    """
    logger.debug(f'>>> {cadpu}')
    data, sw1, sw2 = card.transmit(cadpu.value)
    radpu = RAdpu.build(data, sw1, sw2)
    logger.debug(f'<<< {radpu}')
    return radpu


class RAdpuException(Exception):
    """当出现RAdpu响应错误时抛出的异常类

    可以通过该类的radpu属性获得返回的RAdpu。
    """
    def __init__(self, message: str, radpu: 'RAdpu'):
        super().__init__(message)
        self._radpu = radpu

    @property
    def radpu(self) -> 'RAdpu':
        return self._radpu


def request(card: CardConnection, cadpu: CAdpu) -> bytes:
    """对transmit进行进一步封装和返回处理的方法

    输入为CAdpu，成功响应（SW=9000）的时候输出纯响应数据，不再返回SW。
    当出现SW=61XX的时候，使用GET RESPONSE命令继续获取剩余数据并进行拼接。
    """
    radpu = transmit(card, cadpu)
    if radpu.success:
        return radpu.data
    else:
        last_radpu = radpu
        buffer = bytearray(radpu.data)  # 存储已经读取的数据（如果有）
        while last_radpu.sw1 == 0x61:  # 当出现SW=61XX时，说明还有XX字节的数据等待读取，继续读取
            more_cadpu = CAdpu.build(0x00, 0xc0, 0x00, 0x00, le=radpu.sw2)  # GET RESPONSE 命令
            last_radpu = transmit(card, more_cadpu)
            buffer.extend(last_radpu.data)  # 存储继续读取的数据
            if last_radpu.success:  # 读取成功完成后结束循环
                break
        else:  # 当R-ADPU出现61XX以外的其他错误时
            raise RAdpuException(f'R-ADPU状态码SW错误：{last_radpu}', radpu)
        return bytes(buffer)
